﻿#include "Solar.h"
#include <iostream>
#include "SolarUtil.h"
#include "Lunar.h"
#include "HolidayUtil.h"
#include "Holiday.h"
#include <cmath>
Solar::Solar() :Solar(std::time(nullptr))
{

}


Lunar Solar::lunar()
{
    return Lunar(this);
}

const double Solar::J2000 = 2451545;

Solar::Solar(int year, int month, int day, int hour, int minute, int second)
	: Year(year), Month(month), Day(day), Hour(hour), Minute(minute), Second(second)
{
	// 1582年10月特殊日期检查（格里高利历改革）
	if (1582 == year && 10 == month)
	{
		if (day > 4 && day < 15)
		{
			throw std::invalid_argument("Invalid date: " +
				std::to_string(year) + "-" +
				std::to_string(month) + "-" +
				std::to_string(day) +
				" (Gregorian calendar gap)");
		}
	}
	// 月份有效性检查
	if (month < 1 || month > 12) {
		throw std::invalid_argument("Invalid month: " + std::to_string(month));
	}


	// 日期有效性检查
	if (day < 1 || day > 31) {
		throw std::invalid_argument("Invalid day: " + std::to_string(day));
	}

	if (hour < 0 || hour > 23) {
		throw std::invalid_argument("Invalid hour: " + std::to_string(hour));
	}
	if (minute < 0 || minute > 59) {
		throw std::invalid_argument("Invalid minute: " + std::to_string(minute));
	}
	if (second < 0 || second > 59) {
		throw std::invalid_argument("Invalid second: " + std::to_string(second));
	}

}




Solar::Solar(std::time_t timestamp)
{
	std::tm tm;
#if defined(_WIN32)
	localtime_s(&tm, &timestamp);  // Windows
#else
	localtime_r(&timestamp, &tm);  // Linux/macOS
#endif
	;

	Year = tm.tm_year + 1900;
	Month = tm.tm_mon + 1;
	Day = tm.tm_mday;
	Hour = tm.tm_hour;
	Minute = tm.tm_min;
	Second = tm.tm_sec;

}

/// <summary>
/// 通过儒略日初始化
/// </summary>
/// <param name="julianDay">儒略日</param>
Solar::Solar(double julianDay)
{
	int d = static_cast<int>(julianDay + 0.5);
	double f = julianDay + 0.5 - d;

	// 格里高利历修正（1582年10月15日后）[1,4](@ref)
	if (d >= 2299161) {
		int c = static_cast<int>((d - 1867216.25) / 36524.25);
		d += 1 + c - c / 4;  // 格里历闰年规则修正
	}
	d += 1524;
	int year = static_cast<int>((d - 122.1) / 365.25);
	d -= static_cast<int>(365.25 * year);
	int month = static_cast<int>(d / 30.601);
	d -= static_cast<int>(30.601 * month);

	// 月份范围修正（1-12月）[11](@ref)
	if (month > 13) {
		month -= 13;
		year -= 4715;
	}
	else {
		month -= 1;
		year -= 4716;
	}

	// 小数部分转时间（时/分/秒）[9](@ref)
	f *= 24;
	int hour = static_cast<int>(f);
	f -= hour;
	f *= 60;
	int minute = static_cast<int>(f);
	f -= minute;
	int second = static_cast<int>(std::round(f));

	// 时间进位处理（秒→分→时→日）
	if (second > 59) {
		second -= 60;
		minute++;
	}
	if (minute > 59) {
		minute -= 60;
		hour++;
	}
	if (hour > 23) {
		hour -= 24;
		d += 1;  // 日进位
	}
	Year = year;
	Month = month;
	Day = d;  // 注意：d已包含可能的日进位
	Hour = hour;
	Minute = minute;
	Second = second;
}

Solar Solar::FromYmdHms(int year, int month, int day, int hour, int minute, int second)
{
	return  Solar(year, month, day, hour, minute, second);
}


Solar Solar::FromDate(std::time_t timestamp)
{
	return  Solar(timestamp);
}

Solar Solar::FromJulianDay(double julianDay)
{
	return  Solar(julianDay);
}

bool Solar::LeapYear()
{
	return SolarUtil::IsLeapYear(Year);
}

std::string Solar::Ymd()
{

	std::string yStr = std::to_string(Year);
	while (yStr.length() < 4) {
		yStr = "0" + yStr;
	}

	// 使用字符串流高效格式化月/日
	std::ostringstream oss;
	oss << yStr << "-"
		<< std::setw(2) << std::setfill('0') << Month << "-"
		<< std::setw(2) << std::setfill('0') << Day;

	return oss.str();

}

std::string Solar::YmdHms()
{
	return Ymd() + " " + (Hour < 10 ? "0" : "") + std::to_string(Hour) + ":" + (Minute < 10 ? "0" : "") + std::to_string(Minute) + ":" + (Second < 10 ? "0" : "") + std::to_string(Second);
}


int Solar::Week()
{
	return ((int)(JulianDay() + 0.5) + 7000001) % 7;
}

int Solar::Subtract(Solar& solar)
{
	return SolarUtil::GetDaysBetween(solar.Year, solar.Month, solar.Day, Year, Month, Day);
}

double Solar::JulianDay()
{
	int y = Year;
	int m = Month;
	double d = Day + ((Second * 1.0 / 60 + Minute) / 60 + Hour) / 24.0;
	int n = 0;
	bool g = (y * 372 + m * 31 + static_cast<int>(d)) >= 588829;
	if (m <= 2)
	{
		m += 12;
		y--;
	}
	if (g)
	{
		n = (int)(y * 1.0 / 100);
		n = 2 - n + (int)(n * 1.0 / 4);
	}
	return (int)(365.25 * (y + 4716)) + (int)(30.6001 * (m + 1)) + d + n - 1524.5;

}

std::vector<Solar>* Solar::FromBaZi(std::string& yearGanZhi, std::string& monthGanZhi, std::string& dayGanZhi, std::string& timeGanZhi,
	int sect, int baseYear)
{
	sect = (1 == sect) ? 1 : 2;
	auto l = new std::vector<Solar>();
	// 月地支距寅月的偏移值
	std::string tmpname = monthGanZhi.substr(2);
	auto m = LunarUtil::find(tmpname, LunarUtil::ZHI, -1) - 2;
	if (m < 0)
	{
		m += 12;
	}

	std::string yearname = yearGanZhi.substr(0, 2);
	std::string monthname = monthGanZhi.substr(0, 2);
	// 月天干要一致
	if (((LunarUtil::find(yearname, LunarUtil::GAN, -1) + 1) * 2 + m) % 10 !=
		LunarUtil::find(monthname, LunarUtil::GAN, -1))
	{
		return l;
	}

	// 1年的立春是辛酉，序号57
	auto y = LunarUtil::GetJiaZiIndex(yearGanZhi) - 57;
	if (y < 0)
	{
		y += 60;
	}

	y++;
	// 节令偏移值
	m *= 2;
	// 时辰地支转时刻，子时按零点算
	std::string timename = timeGanZhi.substr(2);
	auto h = LunarUtil::find(timename, LunarUtil::ZHI, -1) * 2;
	std::vector<int>  hours = { h };
	if (0 == h && 2 == sect)
	{
		hours = { 0, 23 };
	}
	auto now = std::chrono::system_clock::now();
	std::time_t t = std::chrono::system_clock::to_time_t(now);

    std::tm now_tm;
//    errno_t err = localtime_s(&now_tm, &t);
	auto startYear = baseYear - 1;
	// 结束年
	auto endYear = now_tm.tm_year + 1900;

	while (y <= endYear)
	{
		if (y >= startYear)
		{

			// 立春为寅月的开始
			Lunar* tmpLunar = Lunar::FromYmdHms(y, 1, 1);
			Solar solarTime = ((tmpLunar->JieQiTable))[Lunar::JIE_QI_IN_USE[4 + m]];
			delete tmpLunar;
			tmpLunar = nullptr;
			// 节令推移，年干支和月干支就都匹配上了
			if (solarTime.Year >= baseYear)
			{

				std::string ganZhi = (solarTime.lunar().DayInGanZhiExact2());
				// 日干支和节令干支的偏移值
				auto d = LunarUtil::GetJiaZiIndex(dayGanZhi) - LunarUtil::GetJiaZiIndex(ganZhi);
				if (d < 0)
				{
					d += 60;
				}

				if (d > 0)
				{
					// 从节令推移天数
					solarTime = solarTime.Next(d);
				}

				for (auto hour : hours)
				{
					auto mi = 0;
					auto s = 0;
					if (d == 0 && hour == solarTime.Hour)
					{
						// 如果正好是节令当天，且小时和节令的小时数相等的极端情况，把分钟和秒钟带上
						mi = solarTime.Minute;
						s = solarTime.Second;
					}

					// 验证一下
					auto solar = FromYmdHms(solarTime.Year, solarTime.Month, solarTime.Day, hour, mi, s);
					Lunar lunar = solar.lunar();
					auto dgz = (2 == sect) ? lunar.DayInGanZhiExact2() : lunar.DayInGanZhiExact();

					if (lunar.YearInGanZhiExact() == yearGanZhi &&
						lunar.MonthInGanZhiExact() == monthGanZhi &&
						dgz == dayGanZhi &&
						lunar.TimeInGanZhi() == timeGanZhi)
					{
						l->push_back(solar);
					}
				}
			}
		}
		y += 60;
	}
	return l;
}





Solar Solar::Next(int days, bool onlyWorkday)
{
	if (!onlyWorkday)
	{
		return NextDay(days);
	}
	Solar solar = Solar(Year, Month, Day, Hour, Minute, Second);
	if (days != 0)
	{
		auto rest = std::abs(days);
		auto add = days < 0 ? -1 : 1;
		while (rest > 0)
		{
			solar = solar.Next(add);
			auto work = true;
			auto holiday = HolidayUtil::GetHoliday(solar.Year, solar.Month, solar.Day);
			if (holiday == nullptr)
			{
				auto week = solar.Week();
				if (0 == week || 6 == week)
				{
					work = false;
				}
			}
			else
			{
				work = holiday->Work;
			}
			if (work)
			{
				rest -= 1;
			}
		}
	}
	return solar;
}


Solar Solar::NextDay(int days)
{
	auto y = Year;
	auto m = Month;
	auto d = Day;
	if (1582 == y && 10 == m)
	{
		if (d > 4)
		{
			d -= 10;
		}
	}
	if (days > 0)
	{
		d += days;
		auto daysInMonth = SolarUtil::GetDaysOfMonth(y, m);
		while (d > daysInMonth)
		{
			d -= daysInMonth;
			m++;
			if (m > 12)
			{
				m = 1;
				y++;
			}
			daysInMonth = SolarUtil::GetDaysOfMonth(y, m);
		}
	}
	else if (days < 0)
	{
		while (d + days <= 0)
		{
			m--;
			if (m < 1)
			{
				m = 12;
				y--;
			}
			d += SolarUtil::GetDaysOfMonth(y, m);
		}
		d += days;
	}
	if (1582 == y && 10 == m)
	{
		if (d > 4)
		{
			d += 10;
		}
	}
	return  Solar(y, m, d, Hour, Minute, Second);
}

